/**
 * 深复制 
 * 要解决 对象的属性也是对象的问题
 * 1 JSON安全 obj先转成JSON字符串,在转换成JSON Obj 不能正确的处理循环引用
 * 2 html dom自带的API structuredClone(value,{transfer:[]}) 
 * 3 递归遍历-具体实现原理 weakMap解决循环引用
 * https://juejin.cn/post/7278103488096829500
 */

//不能解决循环引用
// const deepClone = function(obj){
//   return JSON.parse(JSON.stringify(obj))
// }
//不支持含有循环引用、未实现可迭代接口的自定义对象
// const deepClone2 = function(obj) {
//   return structuredClone(obj)
// }
//解决循环引用问题【简易版本】
function deepClone(obj, visited = new WeakMap()) {
  if (obj instanceof Object === false) return obj;
  if (visited.has(obj)) return visited.get(obj);

  let clone = Array.isArray(obj) ? [] : {};
  visited.set(obj, clone);

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key], visited);
    }
  }

  return clone;
}
// 解决循环引用问题【全面版本】
function deepClone(obj, visited = new WeakMap()) {
  if(obj ==null || typeof obj != "object") return obj;
  if (visited.has(obj)) return visited.get(obj);
  let clone;
  if(obj instanceof Date) return new Date(obj.getTime());
  if(obj instanceof RegExp) return new RegExp(obj);

  if(obj instanceof Map) {
    clone = new Map();
    visited.set(obj,clone);
    for(let [key,value] of obj.entries()) {
      clone.set(deepClone(key,visited), deepClone(value,visited));
    }
  }

  if(obj instanceof Set) {
    clone = new Set();
    visited.set(obj,clone);
    for(let value of obj.values()) {
      clone.add(deepClone(value,visited));
    }
  }

  else if(Array.isArray(obj)) {
    clone = [];
    visited.set(obj,clone);
    for(let value of obj) {
      clone.push(deepClone(value,visited));
    }
  }
  else if(obj instanceof Object) {
    clone = {};
    visited.set(obj,clone);
    for(let key in obj) {
      if(obj.hasOwnProperty(key)) {
        clone[key] = deepClone(obj[key],visited);
      }
    }
  }

  return clone;
}


